import static org.lwjgl.opengl.GL11.GL_AMBIENT_AND_DIFFUSE;
import static org.lwjgl.opengl.GL11.GL_COLOR_MATERIAL;
import static org.lwjgl.opengl.GL11.GL_DIFFUSE;
import static org.lwjgl.opengl.GL11.GL_FRONT;
import static org.lwjgl.opengl.GL11.GL_LIGHT0;
import static org.lwjgl.opengl.GL11.GL_LIGHTING;
import static org.lwjgl.opengl.GL11.GL_LIGHT_MODEL_AMBIENT;
import static org.lwjgl.opengl.GL11.GL_POSITION;
import static org.lwjgl.opengl.GL11.GL_SHININESS;
import static org.lwjgl.opengl.GL11.GL_SMOOTH;
import static org.lwjgl.opengl.GL11.GL_SPECULAR;
import static org.lwjgl.opengl.GL11.glColorMaterial;
import static org.lwjgl.opengl.GL11.glEnable;
import static org.lwjgl.opengl.GL11.glLight;
import static org.lwjgl.opengl.GL11.glLightModel;
import static org.lwjgl.opengl.GL11.glMaterial;
import static org.lwjgl.opengl.GL11.glMaterialf;
import static org.lwjgl.opengl.GL11.glShadeModel;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.border.Border;
import javax.swing.border.EtchedBorder;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.GLU;
import java.awt.FlowLayout;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;	 	
import java.io.ObjectInputStream;	 	
import java.io.ObjectOutputStream;
import java.io.Serializable;

import javax.swing.JTextField;

public class Application{
	
	public Application()
	{
		
	}

	/**
	 * @param args
	 */
	
	float degrees = 0;
	float currentDegrees = 0;
	// Light direction: if last value is 0, then this describes light direction.  If 1, then light position.
    float lightDirection[]= { 0f, 0f, 0f, 0f };
    // Camera position
    static float[] cameraPos = {0f,-10f,30f};
    float[] diffuse = { 1f,  0.0f,   0.3f,1f};
	float[] ambient = { 1f, 0.00f,   0.00f,1f};
	float[] specular = { 1f, 1f,  1f,1f};
	float[] emission = { 0.70f,  .00f,   .00f, 1f};
	float[] shininess = { 0.5f,0f,0f,0f };
	float rotation_speed=0;
	
	final int gridSize=13;
	float gridCellSize=2.5f;
	final int startX=0;
	final int startZ=0;
	final int width=800;
	final int height=600;
	
	boolean stateCarryingLego;
	
	boolean upKeyPressed=false;
	boolean downKeyPressed=false;
	
	// A constant used in navigation
    final float piover180 = 0.0174532925f;

    float cameraRotation = 0f;
    float rotation = 0;

    ArrayList<Lego> legosPlaced = new ArrayList<Lego>();
    Object3D model;
    boolean isHorizontal = true;
    float legoHeight = 0f;
    float[] currentColor = {1f,0f,0f};
    ArrayList<Grid> grids = new ArrayList<Grid>();
    public ArrayList<LastLego> lastLego = new ArrayList<LastLego>();
    boolean deleteLast = false;
  
    
	//----------- Variables added for Lighting Test -----------//
	private FloatBuffer matSpecular;
	private FloatBuffer lightPosition;
	private FloatBuffer whiteLight; 
	private FloatBuffer lModelAmbient;
	//----------- END: Variables added for Lighting Test -----------//
    
	JFrame frame;
	Canvas display_parent;
	JPanel controls;
	
	public void start() {
		controls = setupSideBar();
		frame = new JFrame();
		frame.setSize(1100,600);
		frame.setTitle("Lego Simulation");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setLayout(new BorderLayout());
		display_parent = new Canvas();
		display_parent.setSize(width,height);
		frame.add(display_parent,BorderLayout.CENTER);
		frame.add(controls,BorderLayout.EAST);
		display_parent.setFocusable(true);
		display_parent.requestFocus();
		display_parent.setIgnoreRepaint(true);
		frame.setVisible(true);
		try {
	
			//Display.setDisplayMode(new DisplayMode(width,height));
			Display.setParent(display_parent);
			Display.create();
		} 
		catch (LWJGLException e) {
			e.printStackTrace();
			System.exit(0);
		}
		setup();
		FileReader fr;
		Lego lego = new Lego();
		model = null;
		try{
		fr = new FileReader("files/lego_brick.txt");
		 model= new Object3D(new BufferedReader(fr),false);
		 
		
		}
		catch(Exception ex)
		{
			System.out.println("Caught!");
		}
		
		
		while (!Display.isCloseRequested()) {
		
		// Clear the screen and depth buffer
		
			GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); 
		 
		
		// set the color of the quad (R,G,B,A)
			GL11.glEnable(GL11.GL_BLEND);
			GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

			//Hides the cursor
			if(Mouse.isInsideWindow())
			{
				try {
				      java.nio.IntBuffer image = java.nio.IntBuffer.wrap(new int[]{0});
				      org.lwjgl.input.Cursor cursor = new org.lwjgl.input.Cursor(1,1,0,0,1,image,null);
				      Mouse.setNativeCursor(cursor);
				    }
				    catch(LWJGLException ex) {
				    }
			}
			else
			{
				try {
					Mouse.setNativeCursor(null);
				} catch (LWJGLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		
		if(model!=null){
			
			rotation+=rotation_speed;
	 		if(Math.abs(degrees - currentDegrees)>0.01)
	 		{
	 			if(degrees > currentDegrees)
	 			{
	 				currentDegrees += Math.PI/128;
	 			}
	 			else
	 			{
	 				currentDegrees -= Math.PI/128;
	 			}
	 		}
	 		else
	 		{
	 			if(degrees<0)
	 			{
	 				degrees += Math.PI*2;
	 				currentDegrees += Math.PI*2;
	 			}
	 			else if(degrees> Math.PI*2)
	 			{
	 				degrees -= Math.PI*2;
	 				currentDegrees -= Math.PI*2;
	 			}
	 		}
	 		cameraPos[0] = (float) (30f*Math.sin(currentDegrees));
	 		cameraPos[2] = (float) (30f*Math.cos(currentDegrees));
			GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
			GL11.glMatrixMode(GL11.GL_MODELVIEW);
	        GL11.glLoadIdentity();

	        // set the viewpoint
	        GLU.gluLookAt(cameraPos[0], cameraPos[1], cameraPos[2], // where is the eye
						// look at a point directly in front of camera
						0f, 0f, 0f,
	        			0f, 1f, 0f);
	       GL11.glMaterial(GL11.GL_FRONT, GL11.GL_DIFFUSE, allocFloats(diffuse));
	      //GL11.glMaterial(GL11.GL_FRONT, GL11.GL_AMBIENT, allocFloats(ambient));
	        GL11.glMaterial(GL11.GL_FRONT, GL11.GL_SPECULAR, allocFloats(specular));
	       //GL11.glMaterial(GL11.GL_FRONT, GL11.GL_EMISSION, allocFloats(emission));
	        GL11.glMaterial(GL11.GL_FRONT, GL11.GL_SHININESS, allocFloats(shininess));	
	        GL11.glPushMatrix();
	        
	            
	            
	            
	            float mouseX = Mouse.getX();
	            float mouseY = Mouse.getY();
	            float transX = 4*(6-mouseX/60);
	            float transZ = 4*(5-mouseY/60);
	            if(Math.abs(currentDegrees-Math.PI/2)<0.01)
	            {
	            	float med = transX;
	            	transX = transZ;
	            	transZ = -med;
	            }
	            else if(Math.abs(currentDegrees-((Math.PI*3)/2))<0.01)
	            {
	            	float med = transX;
	            	transX = -transZ;
	            	transZ = med;
	            }
	            else if(Math.abs(currentDegrees-Math.PI)<0.01)
	            {
	            	transX = -transX;
	            	transZ = -transZ;
	            }
	            GL11.glTranslatef(transX, legoHeight, transZ);
	            GL11.glScalef(4, 4, 4);
	            GL11.glColor4f(currentColor[0],currentColor[1],currentColor[2],0.5f);
	            GL11.glRotatef(180, 1, 0, 0);  // turn it
	            if(Mouse.isButtonDown(1))
	            {
	            	isHorizontal = !isHorizontal;
	            }
	            if(!isHorizontal)
	            {
	            	GL11.glRotatef(90,0,1,0);
	            }
	            if(Mouse.isButtonDown(0))
	            {
	            	float half_size = gridCellSize*(gridSize)/2;
	            	for(int i = 0; i < gridSize; i++) //aligning x axis
	        		{
	        			if(Math.abs(-half_size+gridCellSize*i-transX)<1.5)
	        			{
	        				if(isHorizontal)
	        				{
	        					lego.currentX = -half_size+gridCellSize*i;
	        				}
	        				else
	        				{
	        					lego.currentX = -half_size+gridCellSize*(i+0.5f);
	        				}
	        				break;
	        			}
	        		}
	            	for(int i = 0; i < gridSize; i++) //aligning z axis
	        		{
	        			if(Math.abs(-half_size+gridCellSize*i-transZ)<1.5)
	        			{
	        				if(isHorizontal)
	        				{
	        					lego.currentZ = -half_size+gridCellSize*(i+0.5f);
	        				}
	        				else
	        				{
	        					lego.currentZ = -half_size+gridCellSize*i;
	        				}
	        				break;
	        			}
	        		}
	            	//lego.currentX = transX;
	            	//lego.currentZ = transZ;
	            	lego.currentY = legoHeight;
	            	lego.color[0] = currentColor[0];
	            	lego.color[1] = currentColor[1];
	            	lego.color[2] = currentColor[2];
	            	lego.isHorizontal = isHorizontal;
	            	if(lego.currentX != 0.123f && lego.currentZ != 0.123f && validTest(lego))
	            	{
	            		legosPlaced.add(lego);
	            	}
	            	lego = new Lego();
	            }
	            
	            model.opengldraw();
	        
	        //GL11.glScalef(1f, 0.05f, 0.05f);
	        GL11.glPopMatrix();
	        
	        Iterator<Lego> it = legosPlaced.iterator();
	        while(it.hasNext())
	        {
	        	Lego lg = it.next();
	        	if(deleteLast && lg.equals(legosPlaced.get(legosPlaced.size()-1)))
	        	{
	        		it.remove();
	        		deleteLast = false;
	        	}
	        	else
	        	{
	        		GL11.glPushMatrix();
		            
		            GL11.glColor4f(lg.color[0],lg.color[1],lg.color[2],1f);
		            GL11.glTranslatef(lg.currentX, lg.currentY, lg.currentZ);
		            GL11.glScalef(4, 4, 4);
		            GL11.glRotatef(180, 1, 0, 0);  // turn it
		            if(!lg.isHorizontal)
		            {
		            	GL11.glRotatef(90,0,1,0);
		            }
		            
		            model.opengldraw();
		            GL11.glPopMatrix();
	        	}
	        }
	        
	        // Place the light.  Light will move with the rest of the scene
	        setLightPosition(GL11.GL_LIGHT1, lightDirection);
	        rotateCamera();
	        //GL11.glRotatef(-45, 1, 0, 0);
	        GL11.glColor4f(0f,0f,0f,1f);
			this.drawGrid();
		}


			Display.update();

		}

		Display.destroy();

	}
	
	public boolean validTest (Lego lego)
	{
		int legoHeight = (int) (-lego.currentY/1.5);
		if(grids.size() < legoHeight) //False if lego's height is more than 1 level higher than current highest placed lego
		{
			return false;
		}
		if(legoHeight >= 1)
		{
			
		}
		
		int x,z;
		float half_size = gridCellSize*(gridSize)/2;
		//Add filled coords to grids array
		if(lego.isHorizontal)
		{
			x = (int)((lego.currentX+half_size)/gridCellSize);
			z = (int)(-0.5f + ((lego.currentZ+half_size)/gridCellSize))-1;
			if(x == 12 || x == 0 || z == -1) //the lego sticks out of the grid
			{
				return false;
			}
			
			if(legoHeight == grids.size()) //adds another layer to the grid
			{
				grids.add(new Grid());
			}
			
			if(legoHeight > 0)
			{
				if(!(grids.get(legoHeight-1).pt[x][z] || grids.get(legoHeight-1).pt[x-1][z])) //checks if lego is being placed midair
				{
					if(legoHeight < grids.size()-1)
					{
						if(!(grids.get(legoHeight+1).pt[x][z] || grids.get(legoHeight+1).pt[x-1][z])) //checks if lego has blocks above it
						{
							return false;
						}
					}
					else
					{
						return false;
					}
				}
			}
			
			if (grids.get(legoHeight).pt[x][z] || grids.get(legoHeight).pt[x-1][z]) //there is already a lego in one of the squares
			{
				return false;
			}
			
			grids.get(legoHeight).pt[x][z] = true;
			grids.get(legoHeight).pt[x-1][z] = true;
			
			LastLego last = new LastLego();
			last.X1 = x;
			last.X2 = x-1;
			last.Z1 = z;
			last.Z2 = z;
			last.Y = legoHeight;
			
			lastLego.add(last);
		}
		else
		{
			x = (int)(-0.5f + ((lego.currentX+half_size)/gridCellSize));
			z = (int)((lego.currentZ+half_size)/gridCellSize)-1;
			if(x == 12 || z == -1 || z == 0) //the lego sticks out of the grid
			{
				return false;
			}
			
			if(legoHeight == grids.size()) //adds another layer to the grid
			{
				grids.add(new Grid());
			}
			
			if(legoHeight > 0)
			{
				if(!(grids.get(legoHeight-1).pt[x][z] || grids.get(legoHeight-1).pt[x][z-1])) //checks if lego is being placed midair
				{
					if(legoHeight < grids.size()-1)
					{
						if(!(grids.get(legoHeight+1).pt[x][z] || grids.get(legoHeight+1).pt[x][z-1])) //checks if lego has blocks above it
						{
							return false;
						}
					}
					else
					{
						return false;
					}
				}
			}
			
			if (grids.get(legoHeight).pt[x][z] || grids.get(legoHeight).pt[x][z-1]) //there is already a lego in one of the squares
			{
				return false;
			}
			
			grids.get(legoHeight).pt[x][z] = true;
			grids.get(legoHeight).pt[x][z-1] = true;
			
			LastLego last = new LastLego();
			last.X1 = x;
			last.X2 = x;
			last.Z1 = z;
			last.Z2 = z-1;
			last.Y = legoHeight;
			
			lastLego.add(last);
		}
		
		return true;
	}
	
	public void rotateCamera()
	{
		if(Keyboard.next())
		{
			if(Keyboard.isKeyDown(Keyboard.KEY_W))
			{
				legoHeight-=1.5;
			}
			else if(Keyboard.isKeyDown(Keyboard.KEY_S))
			{
				if(legoHeight!=0)
				{
					legoHeight+=1.5;
				}
			}
			else if(Keyboard.isKeyDown(Keyboard.KEY_LEFT))
			{
				//degrees -= 0.01;
				degrees -= Math.PI/2;
				
		 		
			}
			else if(Keyboard.isKeyDown(Keyboard.KEY_RIGHT))
			{
				//degrees += 0.01;
				degrees += Math.PI/2;
			}
		}
		if(Keyboard.isKeyDown(Keyboard.KEY_UP))
		{
			cameraPos[1]+=0.5;
		}
		else if(Keyboard.isKeyDown(Keyboard.KEY_DOWN))
		{
			cameraPos[1]-=0.5;
		}
		
	}
	
	public void setup()
	{
		GL11.glViewport(0, 0, width, height);
		GL11.glMatrixMode(GL11.GL_PROJECTION);

		GL11.glLoadIdentity();
		
		GLU.gluPerspective(300f,1.33f,.1f,500f); 
		
		GL11.glMatrixMode(GL11.GL_MODELVIEW);
		GL11.glEnable(GL11.GL_LIGHTING);
	    GL11.glEnable(GL11.GL_COLOR_MATERIAL);
	    GL11.glEnable(GL11.GL_DEPTH_TEST);
	    GL11.glShadeModel(GL11.GL_SMOOTH);
	    GL11.glClearColor(.5f,.6f,.9f,1f);
		setLight( );
		
		grids.add(new Grid());//add grid for ground level
		
        //setAmbientLight(new float[] { .6f, .6f, .9f, 1f });
 
		
		
	}
	
	public void drawGrid()
	{
		GL11.glLineWidth(2);
		GL11.glBegin(GL11.GL_LINES);
		
		float half_size = gridCellSize*(gridSize)/2;
		for(int i = 0; i < gridSize; i++)
		{
			GL11.glVertex3f(-half_size+gridCellSize*i, 0, half_size);
			GL11.glVertex3f(-half_size+gridCellSize*i, 0, -(gridSize-1)*gridCellSize+half_size);
		}
		for(int i = 0; i < gridSize; i++)
		{
			GL11.glVertex3f(-half_size, 0, half_size-gridCellSize*i);
			GL11.glVertex3f(-half_size+(gridSize-1)*gridCellSize, 0, half_size-gridCellSize*i);
		}
		
		GL11.glEnd();
	}
	
	
	public static void main(String[] argv) {
		Application application = new Application();
		application.start();

	}
	
	public static FloatBuffer allocFloats(float[] floatarray) {
        FloatBuffer fb = ByteBuffer.allocateDirect(floatarray.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
        fb.put(floatarray).flip();
        return fb;
    }
	
	public static FloatBuffer allocFloats(int howmany) {
    	return ByteBuffer.allocateDirect(howmany * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
    }
	
	public void setLight()
	    {
		//----------- Variables & method calls added for Lighting Test -----------//
				initLightArrays();
				glShadeModel(GL_SMOOTH);
				glMaterial(GL_FRONT, GL_SPECULAR, matSpecular);				// sets specular material color
				glMaterialf(GL_FRONT, GL_SHININESS, 50.0f);					// sets shininess
				
				glLight(GL_LIGHT0, GL_POSITION, lightPosition);				// sets light position
				glLight(GL_LIGHT0, GL_SPECULAR, whiteLight);				// sets specular light to white
				glLight(GL_LIGHT0, GL_DIFFUSE, whiteLight);					// sets diffuse light to white
				glLightModel(GL_LIGHT_MODEL_AMBIENT, lModelAmbient);		// global ambient light 
				
				glEnable(GL_LIGHTING);										// enables lighting
				glEnable(GL_LIGHT0);										// enables light0
				
				glEnable(GL_COLOR_MATERIAL);								// enables opengl to use glColor3f to define material color
				glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);			// tell opengl glColor3f effects the ambient and diffuse properties of material
				//----------- END: Variables & method calls added for Lighting Test -----------//
	    }
	
	private void initLightArrays() {
		matSpecular = BufferUtils.createFloatBuffer(4);
		matSpecular.put(1.0f).put(1.0f).put(1.0f).put(1.0f).flip();
		
		lightPosition = BufferUtils.createFloatBuffer(4);
		lightPosition.put(-1.0f).put(0.0f).put(-1.0f).put(0.2f).flip();
		
		whiteLight = BufferUtils.createFloatBuffer(4);
		whiteLight.put(1.0f).put(0.5f).put(1.0f).put(5.0f).flip();
		
		lModelAmbient = BufferUtils.createFloatBuffer(4);
		lModelAmbient.put(0.5f).put(0.5f).put(0.5f).put(1.0f).flip();
	}
	
	/**
     * Set the color of the Global Ambient Light.  Affects all objects in
     * scene regardless of their placement.
     */
    public static void setAmbientLight(float[] ambientLightColor)
    {
        put(allocFloats(4),ambientLightColor);
        GL11.glLightModel(GL11.GL_LIGHT_MODEL_AMBIENT, allocFloats(4));
        
    }
    
    /**
     * Set the position (or direction) of a light to the given xyz.
     */
    public static void setLightPosition(int GLLightHandle, float[] position)
    {
        put(allocFloats(4),position);
        GL11.glLight(GLLightHandle, GL11.GL_POSITION, allocFloats(4));
    }
    
    public static void put(FloatBuffer b, float[] values) {
    	b.clear();
    	b.put(values).flip();
    }
    
    public JPanel setupSideBar(){
    	//others tab
		JPanel other = new JPanel();
		
		JButton undo = new JButton("Remove Last Lego");
		JButton clear = new JButton("Clear Grid");
		
		other.add(undo);
		other.add(clear);
		
		undo.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				if(legosPlaced.size()>0)
				{
					//legosPlaced.remove( legosPlaced.size() - 1);
					deleteLast = true;
					grids.get(lastLego.get(lastLego.size()-1).Y).pt[lastLego.get(lastLego.size()-1).X1][lastLego.get(lastLego.size()-1).Z1] = false;
					grids.get(lastLego.get(lastLego.size()-1).Y).pt[lastLego.get(lastLego.size()-1).X2][lastLego.get(lastLego.size()-1).Z2] = false;
					lastLego.remove(lastLego.size()-1);
				}
				display_parent.requestFocusInWindow();

			}
		});
		
		clear.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				legosPlaced = new ArrayList<Lego>();
				grids = new ArrayList<Grid>();
				grids.add(new Grid());
				lastLego = new ArrayList<LastLego>();
				display_parent.requestFocusInWindow();
				
			}
		});
		
		//load/save tab
		JPanel loadsave = new JPanel();
		//Border savebdr = BorderFactory.createTitledBorder(loweredetched, "Load/Save");
		//loadsave.setBorder(savebdr);
		JButton save = new JButton("Save");
		JButton load = new JButton("Load");
		loadsave.add(save);
		loadsave.add(load);
		
		save.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				saveGame();
			}
		});
		load.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				loadGame();
			}
		});

		
		//color tab
		
		//Border colorbdr = BorderFactory.createTitledBorder(loweredetched, "Choose Color");
		JPanel changecolor = new JPanel();
		//changecolor.setBorder(colorbdr);
		//stuff in JPanel
		JButton red = new JButton("Red");
		JButton green = new JButton("Green");
		JButton blue = new JButton("Blue");
		JButton yellow = new JButton("Yellow");
		JButton white = new JButton("White");
		JButton black = new JButton("Black");
		JButton purple = new JButton("Purple");

		red.setBackground(new Color(255, 0,0));
		green.setBackground(new Color(0,255,0));
		blue.setBackground(new Color(0,0,255));
		yellow.setBackground(new Color(255,255,0));
		white.setBackground(new Color(255,255,255));
		black.setBackground(new Color(0,0,0));
		purple.setBackground(new Color(128,0,255));
		
		//blue.setForeground(new Color(0,0,0));
		//black.setForeground(new Color(0,0,0));

		changecolor.setLayout(new GridLayout(2,2,2,2));
		changecolor.add(red);
		changecolor.add(yellow);
		changecolor.add(green);
		changecolor.add(blue);
		changecolor.add(purple);
		changecolor.add(white);
		changecolor.add(black);

		red.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				currentColor[0] = 1f;
				currentColor[1] = 0f;
				currentColor[2] = 0f;
				System.out.println("red!");
				display_parent.requestFocusInWindow();
			}
		});

		green.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				currentColor[0] = 0f;
				currentColor[1] = 1f;
				currentColor[2] = 0f;
				System.out.println("green!");
				display_parent.requestFocusInWindow();

			}
		});

		blue.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				currentColor[0] = 0f;
				currentColor[1] = 0f;
				currentColor[2] = 1f;
				System.out.println("blue!");
				display_parent.requestFocusInWindow();

			}
		});

		yellow.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				currentColor[0] = 1f;
				currentColor[1] = 1f;
				currentColor[2] = 0f;
				System.out.println("yellow!");
				display_parent.requestFocusInWindow();
			}
		});

		white.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				currentColor[0] = 1f;
				currentColor[1] = 1f;
				currentColor[2] = 1f;
				System.out.println("white!");
				display_parent.requestFocusInWindow();
			}
		});

		black.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				currentColor[0] = 0f;
				currentColor[1] = 0f;
				currentColor[2] = 0f;
				System.out.println("black!");
				display_parent.requestFocusInWindow();
			}
		});

		purple.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				currentColor[0] = 0.5f;
				currentColor[1] = 0f;
				currentColor[2] = 1f;
				System.out.println("purple!");
				display_parent.requestFocusInWindow();
			}
		});
		Border loweredetched = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
		Border savebdr = BorderFactory.createTitledBorder(loweredetched, "Load/Save");
		Border colorbdr = BorderFactory.createTitledBorder(loweredetched, "Colors");
		Border otherbdr = BorderFactory.createTitledBorder(loweredetched, "Other");

		loadsave.setBorder(savebdr);
		changecolor.setBorder(colorbdr);
		other.setBorder(otherbdr);
		
		JPanel sidebar = new JPanel();
		sidebar.setLayout(new GridLayout(3,1));

		sidebar.add(changecolor);
		sidebar.add(other);
		sidebar.add(loadsave);

		JPanel controls = new JPanel();
		controls.add(sidebar);
		return controls;
    }

public  void saveGame(){

		
		
		//creating a new JFrame
		final JFrame savegame = new JFrame();
		//stuff in JFrame
		final JTextField entername = new JTextField("enter name", 50);
		JButton submit = new JButton("Submit");
		JButton cancel = new JButton("Cancel");
		
		//setup JFrame
		savegame.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 20));
		savegame.add(entername);
		savegame.add(submit);
		savegame.add(cancel);
		savegame.setSize( 400, 200);
		savegame.setTitle("Save Game"); 
		savegame.setVisible(true);
		savegame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
	
		submit.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				String savename = entername.getText();
				try{
					final FileOutputStream fos;
					fos = new FileOutputStream("saves/" + savename + ".dat");
					ObjectOutputStream oos = new ObjectOutputStream(fos);
					oos.writeObject(legosPlaced);
					oos.writeObject(grids);
					oos.writeObject(lastLego);
			
					oos.flush();
					fos.close();
				}
				catch(IOException ex){
					System.out.println("Invalid oos");
					System.out.println(ex.getMessage());
					System.out.println( ex.getClass() );
				}	
				savegame.setVisible(false);
				display_parent.requestFocusInWindow();
			}
		});
		cancel.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				savegame.setVisible(false);
				display_parent.requestFocusInWindow();
			}
		});
			
		
	}

	public  void loadGame(){
		
		//creating a new JFrame
		final JFrame loadgame = new JFrame();
		//stuff in JFrame
		final JTextField entername = new JTextField("enter name", 50);
		JButton submit = new JButton("Submit");
		JButton cancel = new JButton("Cancel");
		
		//setup JFrame
		loadgame.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 20));
		loadgame.add(entername);
		loadgame.add(submit);
		loadgame.add(cancel);
		loadgame.setSize( 400, 200);
		loadgame.setTitle("Load Game"); 
		loadgame.setVisible(true);
		loadgame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		
		
		submit.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				try{
					FileInputStream fis = new FileInputStream("saves/" + entername.getText() + ".dat");
					ObjectInputStream ois = new ObjectInputStream(fis);
					legosPlaced = (ArrayList<Lego>)ois.readObject();
					grids = (ArrayList<Grid>) ois.readObject();
					lastLego = (ArrayList<LastLego>) ois.readObject();
					
					fis.close();
					loadgame.setVisible(false);
				}
				catch(IOException ex){
					System.out.println("invalid file");
				}
				catch(ClassNotFoundException ex){
					System.out.println("class not found");
				}
				display_parent.requestFocusInWindow();
				
			}
		});
		cancel.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				loadgame.setVisible(false);
				display_parent.requestFocusInWindow();
			}
		});
	}

}
